package com.um.jdy.app.shop.factory.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.um.jdy.common.commons.manager.WxManager;
import com.um.jdy.app.shop.manager.CartManager;
import com.um.jdy.app.shop.activity.Activity;
import com.um.jdy.app.shop.coupons.Coupons;
import com.um.jdy.app.shop.entity.bo.*;
import com.um.jdy.app.shop.entity.dto.ConfirmGoodsDTO;
import com.um.jdy.app.shop.entity.vo.CreateOrderVO;
import com.um.jdy.app.shop.enums.*;
import com.um.jdy.app.shop.factory.ActivityFactory;
import com.um.jdy.app.shop.factory.CouponsFactory;
import com.um.jdy.app.shop.factory.OrderFactory;
import com.um.jdy.app.shop.manager.ShopOrderManager;
import com.um.jdy.app.queue.enums.DelayedQueueKey;
import com.um.jdy.app.queue.service.RedissonDelayedQueueService;
import com.um.jdy.common.activity.code.ActivityCode;
import com.um.jdy.common.activity.code.CouponsCode;
import com.um.jdy.common.activity.service.CouponsUserService;
import com.um.jdy.common.base.enums.YesOrNo;
import com.um.jdy.common.finance.entity.po.PlatformBill;
import com.um.jdy.common.finance.enums.FinancialEnum;
import com.um.jdy.common.finance.service.PlatformBillService;
import com.um.jdy.common.market.entity.po.Group;
import com.um.jdy.common.market.service.GroupService;
import com.um.jdy.common.member.entity.po.Address;
import com.um.jdy.common.member.entity.po.MemberUser;
import com.um.jdy.common.member.enums.PayEnum;
import com.um.jdy.common.member.service.AddressService;
import com.um.jdy.common.member.service.MemberUserService;
import com.um.jdy.common.shop.code.ShopGoodsCode;
import com.um.jdy.common.shop.code.ShopOrderCode;
import com.um.jdy.common.shop.entity.po.DeliveryTemplate;
import com.um.jdy.common.shop.entity.po.Order;
import com.um.jdy.common.shop.entity.po.OrderGoods;
import com.um.jdy.common.shop.entity.vo.OrderVO;
import com.um.jdy.common.shop.enums.ActivityEnum;
import com.um.jdy.common.shop.enums.CouponsEnum;
import com.um.jdy.common.shop.enums.OrderEnum;
import com.um.jdy.common.shop.service.*;
import com.um.springboot.starter.exception.BusinessException;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.service.impl.BaseService;
import com.um.springboot.starter.utils.JSONUtil;
import com.um.springboot.starter.utils.OrderUtil;
import com.um.springboot.starter.utils.StringUtil;
import com.um.weixin.pay.service.WxBasePayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 订单工厂实现类
 * @author 邓南辉
 * 日期 2021/6/26
 * 版权所有 广州优匠科技有限公司
 */
@Slf4j
@Service
@Transactional
public class OrderFactoryImpl extends BaseService implements OrderFactory {

    @Autowired
    ActivityFactory activityFactory;

    @Autowired
    CouponsFactory couponsFactory;

    @Autowired
    MemberUserService userService;

    @Autowired
    ShopOrderService orderService;

    @Autowired
    CouponsUserService couponsUserService;

    @Autowired
    GoodsOptionService goodsOptionService;

    @Autowired
    CartService cartService;

    @Autowired
    GroupService groupService;

    @Autowired
    DeliveryTemplateService deliveryTemplateService;

    @Autowired
    OrderGoodsService orderGoodsService;

    @Autowired
    CartManager cartManager;

    @Autowired
    PlatformBillService platformBillService;

    @Autowired
    WxManager wxManager;

    @Autowired
    WxBasePayService wxBasePayService;

    @Autowired
    AddressService addressService;

    @Autowired
    ShopOrderManager orderManager;

    @Autowired
    RedissonDelayedQueueService redissonDelayedQueueService;

    /**
     * 生成待支付订单
     *
     * @param goodsBOList
     * @param addressBO
     * @param activityCouponsId
     * @return
     */
    @Override
    public OrderBO confirmOrder(List<GoodsBO> goodsBOList, AddressBO addressBO, String activityCouponsId, String activityCouponsGiftId, OrderEnum.Type type) {
        OrderBO orderBO = new OrderBO();

        //创建活动列表
        List<Activity> activitiesList = activityFactory.createActivities();
        if(type == OrderEnum.Type.Group){
            activitiesList = activitiesList.stream().filter(activity -> activity.getActivityEntity().getType().equals(ActivityEnum.Type.Group.name())).collect(Collectors.toList());
        }else{
            activitiesList = activitiesList.stream().filter(activity -> !activity.getActivityEntity().getType().equals(ActivityEnum.Type.Group.name())).collect(Collectors.toList());
        }

        //创建优惠券列表
        List<Coupons> couponsList = couponsFactory.createCoupons();

        //费用列表
        List<FeeItemBO> feeItemBOList = new ArrayList();


        //第1步：先判断符合活动的商品列表，并进行修改商品的价格为活动价格，赠品活动另外返回赠品列表
        Integer activityFee = 0; //活动优惠金额
        boolean activityIsMeet = false; //记录订单是否一个活动都不参与
        List<FullReduceGiftGoodsBO> fullReduceGiftGoodsBOList = new ArrayList(); //满减活动赠送的商品列表
        List<CouponsBO> fullReduceGiftCouponsBOList = new ArrayList(); //满减活动赠送的卡券列表
        for(Activity activity : activitiesList){
            boolean isMeet = activity.isMeet(goodsBOList);
            if(isMeet){
                activityIsMeet = true;
                activityFee = NumberUtil.add(activityFee,activity.getFee()).intValue();

                //满减活动赠品
                FullReduceGiftGoodsBO fullReduceGiftGoodsBO = activity.getGiftGoods();
                CouponsBO giftCoupons = activity.getGiftCoupons();
                if(null != fullReduceGiftGoodsBO){
                    fullReduceGiftGoodsBOList.add(fullReduceGiftGoodsBO);
                }
                if(null != giftCoupons){
                    fullReduceGiftCouponsBOList.add(giftCoupons);
                }
            }
        }
        if(!activityIsMeet && type == OrderEnum.Type.Group){
            throw new ServiceException(ActivityCode.ActivityNotExist);
        }
        feeItemBOList.add(
                FeeItemBO.builder()
                        .label(OrderFeeItem.Activity.getValue())
                        .fee(activityFee)
                        .build()
        );
        orderBO.setFullReduceGiftCouponsList(fullReduceGiftCouponsBOList);
        orderBO.setFullReduceGiftGoodsList(fullReduceGiftGoodsBOList);

        //第2步：先判断符合优惠券活动的商品列表，并生成优惠项的收费说明，赠品券另外返回赠品列表
        List<Coupons> meetCouponsList = new ArrayList();
        for(Coupons coupons : couponsList){
            boolean isMeet = coupons.isMeet(goodsBOList);
            if(isMeet){
                meetCouponsList.add(coupons);
            }
        }

        //使用优惠券
        Coupons coupons = meetCouponsList.size() > 0 ? meetCouponsList.get(0) : null;//选择默认优惠券
        if(StrUtil.isNotEmpty(activityCouponsId)){//指定优惠券
            List<Coupons> couponsExist = meetCouponsList.stream().filter(item -> item.getCouponsEntity().getActivityCouponsId().equals(activityCouponsId)).limit(1).collect(Collectors.toList());
            coupons = couponsExist.size() > 0 ? couponsExist.get(0) : null;
            if(ObjectUtil.isEmpty(coupons)){
                throw new ServiceException(CouponsCode.NotReachedCoupons);
            }
        }
        if(ObjectUtil.isNotEmpty(coupons)){
            if(StrUtil.isNotEmpty(activityCouponsId) && CouponsEnum.Type.Gift.equals(coupons.getCouponsEntity().getType())){//选择默认赠品
                activityCouponsGiftId = coupons.getCouponsEntity().getGiftGoodsList().get(0).getActivityCouponsGiftsId();
            }
            this.useCoupons(orderBO,coupons,activityCouponsGiftId);
        }
        feeItemBOList.add(
                FeeItemBO.builder()
                        .label(OrderFeeItem.Coupons.getValue())
                        .fee(null != coupons ? orderBO.getCoupons().getMoney() : 0)
                        .build()
        );


        //第3步：根据商品列表及收货地址，并计算运费金额
        Integer freight = 0;
        try {
            freight = this.calcOrderFreight(addressBO, goodsBOList).intValue();
        } catch (BusinessException e) {
            orderBO.setAddressSupported(false);
            orderBO.setAddressMsg(e.getMsg());
        }
        feeItemBOList.add(
                FeeItemBO.builder()
                        .label(OrderFeeItem.Freight.getValue())
                        .fee(freight)
                        .build()
        );


        //支付金额
        //Double payment = goodsEntityList.stream().mapToDouble(item -> item.getPayment()).sum(); 这种写法会导致精度丢失
        Integer payment = 0;
        for (GoodsBO goodsBO : goodsBOList) {
            payment = NumberUtil.add(payment, goodsBO.getPayment()).intValue();
        }
        payment = NumberUtil.add(payment,freight).intValue();


        orderBO.setGoodsList(goodsBOList);
        orderBO.setFeeItemList(feeItemBOList);
        orderBO.setCouponsList(meetCouponsList.stream().map(item -> item.getCouponsEntity()).collect(Collectors.toList()));
        orderBO.setAddress(addressBO);
        orderBO.setPayment(payment < 0 ? 1 : payment);
        orderBO.setFreight(freight);
        orderBO.setActivityDiscountPrice(activityFee);
        // orderBO.setCommission(goodsBOList.stream().mapToInt(item -> item.getCommission()).sum());

        return orderBO;
    }

    /**
     * 生成拼团待支付订单
     *
     * @param goodsBOList
     * @param addressBO
     * @param activityCouponsId
     * @param marketGroupId
     * @return
     */
    @Override
    public OrderBO confirmGroupOrder(List<GoodsBO> goodsBOList, AddressBO addressBO, String activityCouponsId, String activityCouponsGiftId, String marketGroupId) {
        OrderBO orderBO = this.confirmOrder(goodsBOList, addressBO, activityCouponsId,activityCouponsGiftId, OrderEnum.Type.Group);

        GroupBO groupBO = new GroupBO();
        List<UserBO> userBOList = new ArrayList();

        MemberUser user = userService.get();

        //团数据
        if(StrUtil.isEmpty(marketGroupId)){
            groupBO.setGroupNum(orderBO.getGoodsList().get(0).getGroupNum());
            groupBO.setCreateTime(new Date());
        }else{
            Group group = groupService.getEntity(marketGroupId);
            if(null == group || StringUtil.getTrim(group.getStatus()).equals(OrderEnum.GroupStatus.Invalid.name())){
                throw new ServiceException(ActivityCode.GroupNotExist);//已失效
            }

            if(StringUtil.getTrim(group.getStatus()).equals(OrderEnum.GroupStatus.Opened.name())){
                throw new ServiceException(ActivityCode.GroupStarted);//已开团
            }

            groupBO.setCreateTime(group.getCreateTime());
            groupBO.setGroupNum(group.getGroupNum());

            List<GroupOrderBO> orderList = groupService.getViewModelList("get_effective_group_order_list", GroupOrderBO.class,
                    new Object[]{group.getMarketGroupId(),group.getComId()});
            if(orderList.size() >= group.getGroupNum()){
                throw new ServiceException(ActivityCode.GroupStarted);//已成团
            }

            long userExist = orderList.stream().filter(item -> item.getMemberUserId().equals(user.getMemberUserId())).collect(Collectors.counting());
            if(userExist > 0){
                throw new ServiceException(ActivityCode.GroupJoined);//已参加团购
            }

            for(GroupOrderBO order : orderList){
                userBOList.add(UserBO.builder().nickname(order.getNickname()).photo(order.getPhoto()).build());
            }
        }

        userBOList.add(UserBO.builder().nickname(user.getNickname()).photo(user.getPhoto()).build());
        groupBO.setUserList(userBOList);
        orderBO.setGroup(groupBO);

        return orderBO;
    }

    /**
     * 支付订单
     *
     * @param goodsBOList
     * @param addressBO
     * @param activityCouponsId
     * @param remark
     * @return
     */
    @Override
    public CreateOrderVO createOrder(List<GoodsBO> goodsBOList, AddressBO addressBO, String activityCouponsId, String activityCouponsGiftId, String remark, PayEnum.PayWay payWay){
        OrderBO orderBO = this.confirmOrder(goodsBOList, addressBO, activityCouponsId,activityCouponsGiftId, OrderEnum.Type.Normal);
        return this.saveOrder(orderBO, addressBO,remark, OrderEnum.Type.Normal,"", payWay);
    }

    /**
     * 支付拼团订单
     *
     * @param goodsBOList
     * @param addressBO
     * @param activityCouponsId
     * @param marketGroupId
     * @param remark
     * @return
     */
    @Override
    public CreateOrderVO createGroupOrder(List<GoodsBO> goodsBOList, AddressBO addressBO, String activityCouponsId, String activityCouponsGiftId, String marketGroupId, String remark, PayEnum.PayWay payWay) {
        OrderBO orderBO = this.confirmOrder(goodsBOList, addressBO, activityCouponsId,activityCouponsGiftId, OrderEnum.Type.Group);

        List<String> shopOrderIds = new ArrayList<>();

        Group group = new Group();
        if(StrUtil.isEmpty(marketGroupId)){
            group.setMarketActivityGoodsId(orderBO.getGoodsList().get(0).getMarketActivityGoodsId());
            group.setMarketActivityGoodsOptionId(orderBO.getGoodsList().get(0).getMarketActivityGoodsOptionId());
            group.setStatus(OrderEnum.GroupStatus.Unopen.name());
            group.setCreateTime(DateUtil.date());
            group.setGroupNum(orderBO.getGoodsList().get(0).getGroupNum());
            groupService.save(group);

            //添加3小时候关闭拼团延迟队列
            redissonDelayedQueueService.addQueue(group.getMarketGroupId(), 3, TimeUnit.HOURS,
                    DelayedQueueKey.CloseGroup.name());
        }else{
            group = groupService.getEntity(marketGroupId);
            if(null == group || !group.getStatus().equals(OrderEnum.GroupStatus.Unopen.name())){
                throw new ServiceException(ActivityCode.GroupClosed);
            }
            List<GroupOrderBO> orderList = groupService.getViewModelList("get_effective_group_order_list", GroupOrderBO.class,
                    new Object[]{group.getMarketGroupId(),group.getComId()});
            if(orderList.size() >= group.getGroupNum()){
                throw new ServiceException(ActivityCode.GroupStarted);//已成团
            }

            shopOrderIds = orderList.stream().map(item -> item.getShopOrderId()).collect(Collectors.toList());
        }

        CreateOrderVO createOrderVO = this.saveOrder(orderBO, addressBO, remark, OrderEnum.Type.Group, group.getMarketGroupId(), payWay);

        shopOrderIds.add(createOrderVO.getOrder().getShopOrderId());
        group.setShopOrderIds(shopOrderIds.stream().collect(Collectors.joining(",")));
        groupService.updateRow(group);

        return createOrderVO;
    }

    /**
     * 初始化订单列表，获取原价、商品基本信息
     * @param mallGoodsId
     * @param mallGoodsOptionId
     * @param num
     * @return
     */
    @Override
    public List<GoodsBO> initGoodsList(String mallGoodsId, String mallGoodsOptionId, Integer num){
        GoodsOptionBO goods = orderService.getViewModel("get_goods_and_option", GoodsOptionBO.class, new Object[]{mallGoodsId,mallGoodsOptionId,orderService.getComId()});
        if(null == goods){
            throw new ServiceException(ShopGoodsCode.GoodsNotExist);//商品不存在
        }

        if(goods.getOptionStock() < num || num < 1){
            throw new ServiceException(ShopOrderCode.StockLack);//库存不足
        }

        Integer totalPrice = NumberUtil.mul(goods.getOptionPrice(),num).intValue();

        GoodsBO goodsBO = GoodsBO.builder()
                .shopGoodsId(mallGoodsId)
                .shopGoodsOptionId(mallGoodsOptionId)
                .num(num)
                .mallGoodsName(goods.getShopGoodsName())
                .spec(goods.getOptionTitle())
                .skuCode(goods.getSkuCode())
                .thumb(goods.getOptionThumb())
                .isPost(goods.getIsPost())
                .isBack(goods.getIsBack())
                .deliveryTemplateId(goods.getDeliveryTemplateId())
                .price(goods.getOptionPrice())
                .totalPrice(totalPrice)
                .payment(totalPrice)
                .couponsPrice(0)
                .cost(goods.getCost())
                // .goodsType(StringUtil.getTrim(goods.get("goods_type")))
                // .commission(NumberUtil.mul(orderService.getCommission(rateMap,StringUtil.toDouble(goods.get("option_commission"))),StringUtil.toInt(num)))
                .build();

        List<GoodsBO> goodsBOList = new ArrayList();
        goodsBOList.add(goodsBO);

        return goodsBOList;
    }

    /**
     * 初始化订单列表，获取原价、商品基本信息
     * @param goodsList
     */
    @Override
    public List<GoodsBO> initGoodsList(List<ConfirmGoodsDTO> goodsList){

        List<GoodsBO> goodsBOList = new ArrayList();

        for(ConfirmGoodsDTO item : goodsList){
            GoodsOptionBO goods = orderService.getViewModel("get_goods_and_option", GoodsOptionBO.class, new Object[]{item.getShopGoodsId(),item.getShopGoodsOptionId(),orderService.getComId()});
            if(null == goods){
                throw new ServiceException(ShopGoodsCode.GoodsNotExist);//商品不存在
            }

            if(goods.getOptionStock() < item.getNum() || item.getNum() < 1){
                throw new ServiceException(ShopOrderCode.StockLack);//库存不足
            }

            if(StrUtil.isEmpty(goods.getOptionThumb()) && StrUtil.isNotEmpty(goods.getThumb())){
                goods.setOptionThumb(cn.hutool.json.JSONUtil.parseArray(goods.getThumb()).get(0, String.class));
            }

            Integer totalPrice = NumberUtil.mul(goods.getOptionPrice(),item.getNum()).intValue();

            GoodsBO goodsBO = GoodsBO.builder()
                    .shopCartId(item.getShopCartId())
                    .shopGoodsId(item.getShopGoodsId())
                    .shopGoodsOptionId(item.getShopGoodsOptionId())
                    .num(item.getNum())
                    .mallGoodsName(goods.getShopGoodsName())
                    .spec(goods.getOptionTitle())
                    .skuCode(goods.getSkuCode())
                    .thumb(goods.getOptionThumb())
                    .isPost(goods.getIsPost())
                    .isBack(goods.getIsBack())
                    .deliveryTemplateId(goods.getDeliveryTemplateId())
                    .price(goods.getOptionPrice())
                    .totalPrice(totalPrice)
                    .payment(totalPrice)
                    .couponsPrice(0)
                    .cost(goods.getCost())
                    // .commission(NumberUtil.mul(orderService.getCommission(rateMap,StringUtil.toDouble(goods.get("option_commission"))),StringUtil.toInt(item.get("num"))))
                    .build();

            goodsBOList.add(goodsBO);
        }

        return goodsBOList;
    }

    /**
     * 获取收货地址，空为默认收货地址
     * @param accountAddressId
     * @return
     */
    @Override
    public AddressBO getAddress(String accountAddressId){
        Address address;
        if(!StrUtil.isEmpty(accountAddressId)){
            address = addressService.getEntity(accountAddressId);
            if(null == address){
                throw new ServiceException(ShopOrderCode.AddressNotExist);
            }
        }else{
            address = addressService.getEntity(new String[]{"member_user_id","is_default"},new String[]{userService.get().getMemberUserId(),YesOrNo.Yes.name()});
        }
        return BeanUtil.toBean(address, AddressBO.class);
    }

    /**
     * 计算订单运费
     * @return
     */
    @Override
    public Double calcOrderFreight(AddressBO addressBO, List<GoodsBO> goodsBOList) throws BusinessException  {
        if(null == addressBO){
            return 0D;
        }

        String province = addressBO.getProvince();
        String city = addressBO.getCity();
        String area = addressBO.getArea();

        Map<String, DeliveryTemplate> deliveryTemplateMap = goodsBOList.stream()
                .map(item -> item.getDeliveryTemplateId()).distinct()
                .map(item -> deliveryTemplateService.getEntity(item))
                .filter(item -> null != item)
                .collect(Collectors.toMap(item -> item.getShopDeliveryTemplateId(), item -> item));

        double freight = 0;

        // 相同运费模版的合并处理
        for (Map.Entry<String, DeliveryTemplate> entry : deliveryTemplateMap.entrySet()) {

            int num = 0;
            for(GoodsBO goodsBO : goodsBOList){
                if (!StrUtil.equals(entry.getKey(), goodsBO.getDeliveryTemplateId())) {
                    continue;
                }
                if (StringUtil.equals(goodsBO.getIsPost(), YesOrNo.Yes.name())) {
                    continue;
                }
                if (StringUtil.equals(goodsBO.getGoodsType(), "1")) {
                    continue;
                }

                try {
                    checkUnsupportAddress(entry.getValue(), province, city, area, goodsBO.getMallGoodsName());
                } catch (BusinessException e) {
                    throw e;
                }

                num += goodsBO.getNum();
            }

            int goodsFreight = 0;
            if(num > 0){
                DeliveryTemplateFeeBO deliveryTemplateFee = getDeliveryTemplateFeeBO(entry.getValue(), province, city, area);

                // 首重
                goodsFreight = deliveryTemplateFee.getDefaultFirstprice().intValue();

                // 续重
                num -= deliveryTemplateFee.getDefaultFirstnum().intValue();
                if(num > 0){
                    int secondnum = (int) NumberUtil.div(num, deliveryTemplateFee.getDefaultSecondnum().intValue(),0, RoundingMode.UP);
                    goodsFreight = (int) NumberUtil.add(NumberUtil.mul(deliveryTemplateFee.getDefaultSecondprice().intValue(), secondnum), goodsFreight);
                }
            }

            freight = NumberUtil.add(freight,goodsFreight);

        }

        return freight;
    }

    private void checkUnsupportAddress(DeliveryTemplate delivery, String province, String city, String area, String goodsName) throws BusinessException {
        //  不支持配送区域
        List<Map> unsupportAreaList = JSONUtil.parseJSONToList(delivery.getUnsupportArea());
        for(Map item : unsupportAreaList){
            // 省
            List<Map> provinceList = (List) item.get("citys");
            for(Map provinceMap : provinceList){
                if(StringUtil.equals(province,provinceMap.get("title"))){
                    // 市
                    List<Map> cityList = (List) provinceMap.get("children");
                    for(Map cityMap : cityList){
                        if(StringUtil.equals(city,cityMap.get("title"))){
                            // 区
                            List<Map> areaList = (List) cityMap.get("children");
                            for(Map areaMap : areaList){
                                if(StringUtil.equals(area,areaMap.get("title"))){
                                    // throw new ServiceException(StringUtil.getTrim(goodsName)+"不支持配送至"+province+city+area+"!");
                                    // throw new ServiceException("不支持配送至"+province+city+area+"!");
                                    String msg = "抱歉，当前不支持配送至{}，请更换地址";
                                    throw new BusinessException(StrUtil.format(msg, province+city+area));
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private DeliveryTemplateFeeBO getDeliveryTemplateFeeBO (DeliveryTemplate delivery, String province, String city, String area){
        // 全国默认运费
        int defaultFirstnum = delivery.getDefaultFirstnum();
        int defaultFirstprice = delivery.getDefaultFirstprice();
        int defaultSecondnum = delivery.getDefaultSecondnum();
        int defaultSecondprice = delivery.getDefaultSecondprice();

        // 地区运费
        List<Map> supportAreaList = JSONUtil.parseJSONToList(delivery.getAreas());
        loop:
        for(Map item : supportAreaList){
            // 省
            List<Map> provinceList = (List) item.get("citys");
            for(Map provinceMap : provinceList){
                if(StringUtil.equals(province,provinceMap.get("title"))){
                    // 市
                    List<Map> cityList = (List) provinceMap.get("children");
                    for(Map cityMap : cityList){
                        if(StringUtil.equals(city,cityMap.get("title"))){
                            // 区
                            List<Map> areaList = (List) cityMap.get("children");
                            for(Map areaMap : areaList){
                                if(StringUtil.equals(area,areaMap.get("title"))){

                                    defaultFirstnum = StringUtil.toInt(item.get("firstnum"));
                                    defaultFirstprice = StringUtil.toInt(item.get("firstprice"));
                                    defaultSecondnum = StringUtil.toInt(item.get("secondnum"));
                                    defaultSecondprice = StringUtil.toInt(item.get("secondprice"));

                                    break loop;
                                }
                            }
                        }
                    }
                }
            }
        }

        return DeliveryTemplateFeeBO.builder()
                .defaultFirstnum(defaultFirstnum)
                .defaultFirstprice(defaultFirstprice)
                .defaultSecondnum(defaultSecondnum)
                .defaultSecondprice(defaultSecondprice)
                .build();
    }

    private CreateOrderVO saveOrder(OrderBO orderBO, AddressBO addressBO, String remark, OrderEnum.Type type, String marketGroupId, PayEnum.PayWay payWay){
        if(!orderBO.isAddressSupported()){
            throw new ServiceException(orderBO.getAddressMsg());
        }

        MemberUser user = userService.get();

        //保存订单
        Order order = new Order();
        order.setMemberUserId(user.getMemberUserId());
        order.setProvince(addressBO.getProvince());
        order.setCity(addressBO.getCity());
        order.setArea(addressBO.getArea());
        order.setAddress(addressBO.getAddress());
        order.setLinkman(addressBO.getName());
        order.setPhone(addressBO.getPhone());
        order.setCreateTime(DateUtil.date());
        order.setRemark(remark);
        order.setOrderNo(OrderUtil.getOrderNo());
        order.setOutTradeNo(OrderUtil.getWxOrderNo());
        order.setTotalGoodsPrice(orderBO.getGoodsList().stream().mapToInt(GoodsBO::getTotalPrice).sum());
        order.setPayment(orderBO.getPayment());
        order.setCouponsPrice(orderBO.getGoodsList().stream().mapToInt(GoodsBO::getCouponsPrice).sum());
        order.setDeliveryPrice(orderBO.getFreight());
        order.setActivityCouponsUserId(null != orderBO.getCoupons() ? orderBO.getCoupons().getActivityCouponsUserId() : null);
        order.setPayWay(payWay.name());
        order.setActivityDiscountPrice(orderBO.getActivityDiscountPrice());
        //拼团订单
        if(type == OrderEnum.Type.Group){
            order.setMarketGroupId(marketGroupId);
            order.setType(type.name());
        }

        //保存满减活动赠优惠券id
        List<String> fullReduceGiftCouponsIdList = orderBO.getFullReduceGiftCouponsList().stream().map(couponsEntity -> couponsEntity.getActivityCouponsId()).collect(Collectors.toList());
        if(fullReduceGiftCouponsIdList.size() > 0){
            order.setGiftActivityCouponsIds(JSONUtil.toJSONString(fullReduceGiftCouponsIdList));
        }

        orderService.save(order);

        //保存订单商品
        for (GoodsBO goodsBO : orderBO.getGoodsList()) {
            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setShopOrderId(order.getShopOrderId());
            orderGoods.setMemberUserId(user.getMemberUserId());
            orderGoods.setShopGoodsId(goodsBO.getShopGoodsId());
            orderGoods.setShopGoodsOptionId(goodsBO.getShopGoodsOptionId());
            orderGoods.setNum(goodsBO.getNum());
            orderGoods.setGoodsName(goodsBO.getMallGoodsName());
            orderGoods.setGoodsThumb(goodsBO.getThumb());
            orderGoods.setSpec(goodsBO.getSpec());
            orderGoods.setSkuCode(goodsBO.getSkuCode());
            orderGoods.setCreateTime(order.getCreateTime());
            orderGoods.setGoodsPrice(goodsBO.getPrice());
            orderGoods.setActivityGoodsPrice(goodsBO.getActivityPrice());
            orderGoods.setTotalGoodsPrice(goodsBO.getTotalPrice());
            orderGoods.setCouponsPrice(goodsBO.getCouponsPrice());
            orderGoods.setPayment(goodsBO.getPayment());
            orderGoods.setActivityType(goodsBO.getActivityType());
            orderGoods.setMarketActivityId(goodsBO.getMarketActivityId());
            orderGoods.setMarketActivityGoodsId(goodsBO.getMarketActivityGoodsId());
            orderGoods.setMarketActivityGoodsOptionId(goodsBO.getMarketActivityGoodsOptionId());
            orderGoods.setIsBack(goodsBO.getIsBack());
            orderGoodsService.save(orderGoods);

            //减库存
            goodsOptionService.reduceStock(orderGoods.getShopGoodsOptionId(), orderGoods.getNum());
            goodsOptionService.reduceActivityStock(orderGoods.getMarketActivityGoodsOptionId(), orderGoods.getNum());

        }

        //保存优惠券赠品
        CouponsGiftGoodsBO couponsGiftGoodsBO = orderBO.getCouponsGiftGoods();
        if(null != couponsGiftGoodsBO){
            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setShopOrderId(order.getShopOrderId());
            orderGoods.setMemberUserId(order.getMemberUserId());
            orderGoods.setCreateTime(order.getCreateTime());
            orderGoods.setType(OrderEnum.GoodsType.Coupons.name());
            orderGoods.setShopGoodsId(couponsGiftGoodsBO.getShopGoodsId());
            orderGoods.setShopGoodsOptionId(couponsGiftGoodsBO.getShopGoodsOptionId());
            orderGoods.setNum(couponsGiftGoodsBO.getNum());
            orderGoods.setGoodsName(couponsGiftGoodsBO.getShopGoodsName());
            orderGoods.setGoodsThumb(couponsGiftGoodsBO.getThumb());
            orderGoods.setSpec(couponsGiftGoodsBO.getSpec());
            orderGoods.setGoodsPrice(couponsGiftGoodsBO.getPrice());
            orderGoods.setActivityGoodsPrice(couponsGiftGoodsBO.getActivityPrice());
            orderGoods.setTotalGoodsPrice(couponsGiftGoodsBO.getTotalPrice());
            orderGoods.setCouponsPrice(couponsGiftGoodsBO.getCouponsPrice());
            orderGoods.setPayment(couponsGiftGoodsBO.getPayment());
            orderGoodsService.save(orderGoods);

            //减库存
            goodsOptionService.reduceStock(orderGoods.getShopGoodsOptionId(), orderGoods.getNum());
        }

        //保存满减赠品
        List<FullReduceGiftGoodsBO> fullReduceGiftGoodsBOList = orderBO.getFullReduceGiftGoodsList();
        for (FullReduceGiftGoodsBO fullReduceGiftGoodsBO : fullReduceGiftGoodsBOList) {
            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setShopOrderId(order.getShopOrderId());
            orderGoods.setMemberUserId(order.getShopOrderId());
            orderGoods.setCreateTime(order.getCreateTime());
            orderGoods.setType(OrderEnum.GoodsType.FullReduce.name());
            orderGoods.setShopGoodsId(fullReduceGiftGoodsBO.getShopGoodsId());
            orderGoods.setShopGoodsOptionId(fullReduceGiftGoodsBO.getShopGoodsOptionId());
            orderGoods.setNum(fullReduceGiftGoodsBO.getNum());
            orderGoods.setGoodsName(fullReduceGiftGoodsBO.getShopGoodsName());
            orderGoods.setGoodsThumb(fullReduceGiftGoodsBO.getThumb());
            orderGoods.setSpec(fullReduceGiftGoodsBO.getSpec());
            orderGoods.setGoodsPrice(fullReduceGiftGoodsBO.getPrice());
            orderGoods.setActivityGoodsPrice(0);
            orderGoods.setTotalGoodsPrice(fullReduceGiftGoodsBO.getTotalPrice());
            orderGoods.setCouponsPrice(0);
            orderGoods.setPayment(fullReduceGiftGoodsBO.getPayment());
            orderGoods.setMarketActivityId(fullReduceGiftGoodsBO.getMarketActivityId());
            orderGoodsService.save(orderGoods);

            //减库存
            goodsOptionService.reduceStock(orderGoods.getShopGoodsOptionId(), orderGoods.getNum());
        }

        if(null != orderBO.getCoupons()){
            couponsUserService.saveCouponsUse(orderBO.getCoupons().getActivityCouponsUserId());
        }

        //移除购物车商品
        cartManager.delete(orderBO.getGoodsList().stream()
                .filter(goodsEntity -> StrUtil.isNotEmpty(goodsEntity.getShopCartId()))
                .map(goodsEntity -> goodsEntity.getShopCartId())
                .collect(Collectors.toList()));

        String orderNo = order.getOrderNo();
        String outTradeNo = order.getOutTradeNo();
        int payment = order.getPayment();

        //支付金额账单
        saveBill(orderNo, outTradeNo, payment, FinancialEnum.IncomeOrExpend.Income.name(), FinancialEnum.PlatformBillEvent.GoodsIncome.name(), FinancialEnum.BillStatus.NotEffective.name(), "");
        //微信支付手续费0.0006
        saveBill(orderNo, outTradeNo, (int) NumberUtil.mul(payment, 0.0006), FinancialEnum.IncomeOrExpend.Expend.name(), FinancialEnum.PlatformBillEvent.PayFee.name(), FinancialEnum.BillStatus.NotEffective.name(), "");

        CreateOrderVO createOrderVO = new CreateOrderVO();
        createOrderVO.setOrder(BeanUtil.toBean(order, OrderVO.class));
        createOrderVO.setPay(orderManager.pay(order, user.getMiniOpenId()));

        //添加超时未支付延迟队列 TODO 测试3分钟过期
        redissonDelayedQueueService.addQueue(order.getShopOrderId(), 30, TimeUnit.MINUTES,
                DelayedQueueKey.CancelOrder.name());

        return createOrderVO;
    }

    private void useCoupons(OrderBO orderBO, Coupons coupons, String activityCouponsGiftId){
        switch (CouponsEnum.Type.valueOf(coupons.getCouponsEntity().getType())){
            case Coupons:
            case Voucher:
                int totalCouponsPrice = 0;
                //计算减去优惠金额后的支付价格
                for (int index = 0; index < coupons.getCouponsGoods().size(); index++) {
                    GoodsBO goodsBO = coupons.getCouponsGoods().get(index);

                    Integer couponsPrice;
                    if(index + 1 < coupons.getCouponsGoods().size()){
                        couponsPrice = NumberUtil.round(NumberUtil.mul(NumberUtil.div(goodsBO.getTotalPrice(),coupons.getCouponsEntity().getJoinCouponsPrice()),coupons.getCouponsEntity().getMoney()),2).intValue();
                    }else{
                        couponsPrice = coupons.getCouponsEntity().getMoney() - totalCouponsPrice;
                    }

                    Integer payment = NumberUtil.sub(goodsBO.getTotalPrice(), couponsPrice).intValue();
                    goodsBO.setCouponsPrice(couponsPrice);
                    goodsBO.setPayment(payment);

                    totalCouponsPrice += couponsPrice;
                }
                break;

            case Gift:
                if(!StrUtil.isEmpty(activityCouponsGiftId)){
                    CouponsGiftGoodsBO couponsGiftGoodsBO = coupons.getCouponsEntity().getGiftGoodsList().stream().filter(giftGoodsEntity -> giftGoodsEntity.getActivityCouponsGiftsId().equals(activityCouponsGiftId)).collect(Collectors.toList()).get(0);
                    if(null == couponsGiftGoodsBO){
                        throw new ServiceException(ShopOrderCode.GiftGoodsNotExist); //选择赠品错误
                    }

                    orderBO.setCouponsGiftGoods(couponsGiftGoodsBO);
                }
                break;
        }
        orderBO.setCoupons(coupons.getCouponsEntity());
    }

    /**
     * 保存账单
     *
     * @param orderNo
     * @param amount
     * @param event
     * @param type
     * @param status
     * @param remark
     * @return
     */
    private boolean saveBill( String orderNo, String wxOrderNo, int amount, String type, String event, String status, String remark) {
        PlatformBill bill = new PlatformBill();
        bill.setNo(OrderUtil.getOrderNo());
        bill.setOrderNo(orderNo);
        bill.setOutTradeNo(wxOrderNo);
        bill.setAmount(amount);
        bill.setEvent(event);
        bill.setType(type);
        bill.setStatus(status);
        bill.setRemark(remark);
        bill.setCreateTime(DateUtil.date());
        return platformBillService.save(bill);
    }
}
